package core;

import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;

import towers.Tower;

/**
 * @author onbekend
 * @version 1.1
 * @since 2011-04-11
 */
public class Mouse extends MouseAdapter implements MouseMotionListener {

	private Tower selectedItem;
	private Model model;
	private Point mouseDot = new Point();

	/**
	 * 
	 * @param model het model
	 */
	/* /// Constructor //////////////////////////////////////// */
	public Mouse(Model model) {
		this.model = model;
	}
	
	/**
	 * 
	 * @param p het punt waar op geklikt is
	 * @return true, als het punt in het battlefield ligt, anders return false
	 */
	/* /// clickedInField //////////////////////////////////////// */
	private boolean clickedInField(Point p) {
		return (p.x < Model.battlefieldWidth && p.y < Model.battlefieldHeight);
	}

	/**
	 * Gaat mousepoint doorgeven aan een model class
	 */
	/* /// mouseClicked //////////////////////////////////////// */
	public void mouseClicked(MouseEvent e) {
		Point p = e.getPoint();
		if (e.getButton() == MouseEvent.BUTTON1) {
			/**
			 * moet naar (een) model
			 */
			// als er in het veld geklikt is
			if (clickedInField(p)) {
				// als er voorheen een tower geselecteerd is
				if (this.selectedItem != null) {
					// als de vorige toren op het veld staat
					if (this.selectedItem.position != null) {
						// als waar je nu op klikt een toren is
						if (this.getTowerByPoint(p) != null) {
							// de toren waar op geklikt is
							this.selectedItem = this.getTowerByPoint(p);
							// notify mijn obeservers maar eens lekker goed
							this.model.notifyObservers("new tower selected");
							model.repaint();
						} else {
							// null want je klikte nergens op
							this.selectedItem = null;
							model.repaint();

						}
					}
					// de toren wie voorheen geselecteerd is heeft geen punten
					// dit staat dus voor een nieuw te bouwen toren
					else {
						if (!this.placeOccupied(p)) {

							// omdat de tower in het midden moet komen als je
							// hem ergens wilt bouwe
							p.x -= selectedItem.getSize().getWidth() / 2;
							p.y -= selectedItem.getSize().getHeight() / 2;

							if (model.buyTower(selectedItem, new Point2D.Double((double) p.x, (double) p.y))) {
								this.selectedItem = null;
								System.out.println("Nieuwe tower gebouwd");
							}
						} else {
							System.out.println("Hier bouwen is niet toegestaan");
						}
					} // als er geen last selected item is
				} else {
					if (this.getTowerByPoint(p) != null) {
						// de toren waar op geklikt is
						this.selectedItem = this.getTowerByPoint(p);
						// notify mijn obeservers maar eens lekker goed
						this.model.notifyObservers("new tower selected");
						model.repaint();
					} else {
						// null want je klikte nergens op
						this.selectedItem = null;
						model.repaint();
					}
				}
			}
		} else if (e.getButton() == MouseEvent.BUTTON3) {
			selectedItem = null;
			model.repaint();
		}
	}

	/* /// getSelectedItem //////////////////////////////////////// */
	public Tower getSelectedItem() {
		return this.selectedItem;
	}

	/* /// setSelectedItem //////////////////////////////////////// */
	public void setSelectedItem(Tower t) {
		this.selectedItem = t;
	}

	/**
	 * @param p het punt waar op geklikt is
	 * @return true, als het punt op de weg en de basis ligt en niet in het veld ligt 
	 * of als er genoeg ruimte is links en rechts van de geklikte plaats. 
	 * Anders return false.
	 */
	/* /// placeOccupied //////////////////////////////////////// */
	public boolean placeOccupied(Point p) {
		for (Tower t : model.getTowers()) {
			// omdat de toren wordt gebouw waar je klikt (midden) moet er links
			// en rechts
			// de helft van de toren beschikbaar zijn
			if (t.bounds.intersects(p.x - (selectedItem.getSize().getWidth() / 2), p.y
					- (selectedItem.getSize().getHeight() / 2), selectedItem.getSize().getWidth(), selectedItem
					.getSize().getHeight())) {
				return true;
			}
		}
		if (isOnRoad(p) || isOnBase(p) || !isInField(p)) {
			return true;
		}
		return false;
	}

	/* /// isOnRoad //////////////////////////////////////// */
	private boolean isOnRoad(Point p) {
		for (Polygon y : model.getMap().getPolygonArray()) {
			if (y.intersects((p.x - selectedItem.getImage().getIconWidth() / 2), (p.y - selectedItem.getImage()
					.getIconHeight() / 2), selectedItem.getImage().getIconWidth(), selectedItem.getImage()
					.getIconHeight())) {
				return true;
			}
		}
		return false;
		// return model.getMap().getPolygon().intersects(p.x, p.y,
		// selectedItem.image.getIconWidth(), selectedItem.image.getIconHeight()
		// );
	}

	/* /// isOnBase //////////////////////////////////////// */
	private boolean isOnBase(Point p) {
		return model
				.getMap()
				.getBase()
				.getBounds()
				.intersects((p.x - selectedItem.getImage().getIconWidth() / 2),
						(p.y - selectedItem.getImage().getIconHeight() / 2), selectedItem.getImage().getIconWidth(),
						selectedItem.getImage().getIconHeight());
	}

	/* /// isInField //////////////////////////////////////// */
	private boolean isInField(Point p) {
		if (p.x >= (selectedItem.getSize().getWidth() / 2) && p.y >= (selectedItem.getSize().getHeight() / 2)
				&& p.x < (Model.battlefieldWidth - selectedItem.getSize().getWidth() / 2)
				&& p.y < (Model.battlefieldHeight - selectedItem.getSize().getHeight() / 2))
			return true;

		return false;

	}

	/* /// getTowerByPoint //////////////////////////////////////// */
	public Tower getTowerByPoint(Point p) {
		for (Tower t : model.getTowers()) {
			if (t.bounds.intersects(p.x, p.y, 5, 5)) {
				return t;
			}
		}

		return null;
	}

	/* /// checkNewTower //////////////////////////////////////// */
	public boolean checkNewTower() {
		return (this.selectedItem.position == null);
	}

	/* /// getClickLocation //////////////////////////////////////// */
	public Point getClickLocation() {
		return new Point();
	}

	/**
	 * Het punt van de muis wordt opnieuw berekend en getekend.
	 * @param e De actie die je uitvoert met de muis.
	 */
	/* /// mouseMoved //////////////////////////////////////// */
	public void mouseMoved(MouseEvent e) {
		// controleren of er een geselecteerde toren is, die nog niet geplaatst
		// is.
		if (getSelectedItem() != null && getSelectedItem().position == null) {
			// het punt van de mouse updaten en tekenen
			mouseDot = e.getPoint();
			model.repaint();
		} else {
			// zorgen dat het punt uit beeld is bij niet bestaande of reeds
			// gebouwde toren.
			mouseDot.x = 900;
			mouseDot.y = 900;
		}
	}

	/* /// getMouseDot //////////////////////////////////////// */
	public Point getMouseDot() {
		return mouseDot;
	}
}
